/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.letmeshare.stockkeeper.purchase.module;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import org.letmeshare.stockkeeper.common.Status;
import org.letmeshare.stockkeeper.purchase.entities.Purchase;
import org.letmeshare.stockkeeper.purchase.entities.PurchaseEntry;
import org.letmeshare.stockkeeper.stock.entities.Item;
import org.letmeshare.stockkeeper.stock.module.StockModule;
import org.letmeshare.stockkeeper.util.DateUtil;

/**
 *
 * @author gAmE wOrLd
 */
public class PurchaseModule {

    private EntityManager em;

    public static PurchaseModule getInstance(EntityManager em) {
        if (em == null) {
            return null;
        }
        return new PurchaseModule(em);
    }

    private PurchaseModule(EntityManager em) {
        this.em = em;
    }

    public void commitPurchase(Purchase purchase) {
        if (purchase == null) {
            throw new IllegalArgumentException("Purchase required");
        }
        purchase.validate();
        if (purchase.getId() == null) {
            em.persist(purchase);
        } else {
            em.merge(purchase);
        }
        em.flush();
    }

    public void cancelPurchase(Purchase purchase) {
        if (purchase == null) {
            throw new IllegalArgumentException("Bill required");
        }
        purchase.validate();
        if (purchase.getStatus().equals(Status.CANCELLED)) {
            throw new IllegalArgumentException("Bill already cancelled");
        }
        purchase.setStatus(Status.CANCELLED);
        StockModule stockModule = StockModule.getInstance(em);
        for (PurchaseEntry entry : purchase.getEntries()) {
            if (entry != null) {
                stockModule.consume(entry.getItem(), entry.getQty());
            }
        }
        em.merge(purchase);
    }

    public Purchase getPurchase(String id) {
        if (id == null) {
            throw new IllegalArgumentException("Id required");
        }
        return em.find(Purchase.class, id);
    }

    public List<Purchase> getAllPurchases() {
        Query query = em.createQuery("SELECT purchase FROM Purchase purchase");
        return query.getResultList();
    }

    public List<Purchase> getAllPurchasesBilledOn(Date date) {
        if (date == null) {
            throw new IllegalArgumentException("Date required");
        }
        try {
            Query query = em.createQuery("SELECT purchase FROM Purchase purchase "
                    + "WHERE purchase.billedOn>=:startDate AND "
                    + "purchase.billedOn<=:endDate");
            query.setParameter("startDate", DateUtil.beginning(date));
            query.setParameter("endDate", DateUtil.end(date));
            return query.getResultList();
        } catch (ParseException ex) {
            throw new IllegalArgumentException("Invalid date");
        }
    }

    public List<Purchase> getAllActivePurchases() {
        Query query = em.createQuery("SELECT purchase FROM Purchase purchase "
                + "WHERE purchase.status<>:status");
        query.setParameter("status", Status.CANCELLED);
        return query.getResultList();
    }

    public List<Purchase> getActivePurchasesBilledOn(Date date) {
        if (date == null) {
            throw new IllegalArgumentException("Date required");
        }
        try {
            Query query = em.createQuery("SELECT purchase FROM Purchase purchase "
                    + "WHERE purchase.billedOn>=:startDate AND "
                    + "purchase.billedOn<=:endDate AND purchase.status<>:status");
            query.setParameter("status", Status.CANCELLED);
            query.setParameter("startDate", DateUtil.beginning(date));
            query.setParameter("endDate", DateUtil.end(date));
            return query.getResultList();
        } catch (ParseException ex) {
            throw new IllegalArgumentException("Invalid date");
        }
    }

    public List<Purchase> getAllCancelledPurchases() {
        Query query = em.createQuery("SELECT purchase FROM Purchase purchase "
                + "WHERE purchase.status=:status");
        query.setParameter("status", Status.CANCELLED);
        return query.getResultList();
    }

    public List<Purchase> getCancelledPurchasesBilledOn(Date date) {
        if (date == null) {
            throw new IllegalArgumentException("Date required");
        }
        try {
            Query query = em.createQuery("SELECT purchase FROM Purchase purchase "
                    + "WHERE purchase.billedOn>=:startDate AND "
                    + "purchase.billedOn<=:endDate AND purchase.status=:status");
            query.setParameter("status", Status.CANCELLED);
            query.setParameter("startDate", DateUtil.beginning(date));
            query.setParameter("endDate", DateUtil.end(date));
            return query.getResultList();
        } catch (ParseException ex) {
            throw new IllegalArgumentException("Invalid date");
        }
    }

    public List<PurchaseEntry> getAllPurchaseEntriesForItem(Item item) {
        if (item == null) {
            throw new IllegalArgumentException("Item required");
        }
        Query query = em.createQuery("SELECT purchaseEntry FROM Purchase purchase "
                + "JOIN purchase.entries purchaseEntry WHERE purchaseEntry.item=:item");
        query.setParameter("item", item);
        return query.getResultList();
    }

    public List<PurchaseEntry> getActivePurchaseEntriesForItem(Item item) {
        if (item == null) {
            throw new IllegalArgumentException("Item required");
        }
        Query query = em.createQuery("SELECT purchaseEntry FROM Purchase purchase "
                + "JOIN purchase.entries purchaseEntry WHERE purchase.status<>:status "
                + "AND purchaseEntry.item=:item");
        query.setParameter("status", Status.CANCELLED);
        query.setParameter("item", item);
        return query.getResultList();
    }

    public List<PurchaseEntry> getCancelledPurchaseEntriesForItem(Item item) {
        if (item == null) {
            throw new IllegalArgumentException("Item required");
        }
        Query query = em.createQuery("SELECT purchaseEntry FROM Purchase purchase "
                + "JOIN purchase.entries purchaseEntry WHERE purchase.status=:status "
                + "AND purchaseEntry.item=:item");
        query.setParameter("item", item);
        query.setParameter("status", Status.CANCELLED);
        return query.getResultList();
    }

    public List<Purchase> getAllPurchasesBetween(Date startDate, Date endDate) {
        try {
            if (startDate == null || endDate == null || startDate.compareTo(endDate) > 0) {//TODO temporary management
                return null;
            }
            Query query = em.createQuery("SELECT purchase FROM Purchase purchase "
                    + "WHERE purchase.billedOn>=:startDate AND purchase.billedOn<=:endDate");
            query.setParameter("startDate", DateUtil.beginning(startDate));
            query.setParameter("endDate", DateUtil.end(endDate));
            return query.getResultList();
        } catch (ParseException ex) {
            throw new IllegalArgumentException("Invalid date");
        }
    }

    public List<Purchase> getActivePurchasesBetween(Date startDate, Date endDate) {
        try {
            if (startDate == null || endDate == null || startDate.compareTo(endDate) > 0) {//TODO temporary management
                return null;
            }
            Query query = em.createQuery("SELECT purchase FROM Purchase purchase "
                    + "WHERE purchase.billedOn>=:startDate AND purchase.billedOn<=:endDate "
                    + "AND purchase.status<>:status");
            query.setParameter("startDate", DateUtil.beginning(startDate));
            query.setParameter("endDate", DateUtil.end(endDate));
            query.setParameter("status", Status.CANCELLED);
            return query.getResultList();
        } catch (ParseException ex) {
            throw new IllegalArgumentException("Invalid date");
        }
    }

    public List<Purchase> getCancelledPurchasesBetween(Date startDate, Date endDate) {
        try {
            if (startDate == null || endDate == null || startDate.compareTo(endDate) > 0) {//TODO temporary management
                return null;
            }
            Query query = em.createQuery("SELECT purchase FROM Purchase purchase "
                    + "WHERE purchase.billedOn>=:startDate AND purchase.billedOn<=:endDate "
                    + "AND purchase.status=:status");
            query.setParameter("startDate", DateUtil.beginning(startDate));
            query.setParameter("endDate", DateUtil.end(endDate));
            query.setParameter("status", Status.CANCELLED);
            return query.getResultList();
        } catch (ParseException ex) {
            throw new IllegalArgumentException("Invalid date");
        }
    }
}
